#include "SerialCommunicator.h"
#include "CoreException.h"
#include "System.h"
#include <fcntl.h>
#include <cstring>

namespace Core {

    SerialCommunicator::SerialCommunicator(std::string pDevice)
    {
        mDevice = pDevice;
    }

    void SerialCommunicator::Open() {
        mFileDescriptor = open(mDevice.c_str() , O_RDWR | O_NOCTTY | O_NDELAY);

        if (mFileDescriptor < 0)
            Error();

        tcgetattr(mFileDescriptor , &mOldOptions);
        bzero(&mNewOptions, sizeof(mNewOptions));
        mNewOptions.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
        mNewOptions.c_iflag = IGNPAR | ICRNL;
        mNewOptions.c_oflag = 0;
        //mNewOptions.c_lflag = ICANON;

        mNewOptions.c_cc[VINTR]    = 0;     /* Ctrl-c */
        mNewOptions.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
        mNewOptions.c_cc[VERASE]   = 0;     /* del */
        mNewOptions.c_cc[VKILL]    = 0;     /* @ */
        mNewOptions.c_cc[VEOF]     = 4;     /* Ctrl-d */
        mNewOptions.c_cc[VTIME]    = 0;     /* inter-character timer unused */
        mNewOptions.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
        mNewOptions.c_cc[VSWTC]    = 0;     /* '\0' */
        mNewOptions.c_cc[VSTART]   = 0;     /* Ctrl-q */
        mNewOptions.c_cc[VSTOP]    = 0;     /* Ctrl-s */
        mNewOptions.c_cc[VSUSP]    = 0;     /* Ctrl-z */
        mNewOptions.c_cc[VEOL]     = 0;     /* '\0' */
        mNewOptions.c_cc[VREPRINT] = 0;     /* Ctrl-r */
        mNewOptions.c_cc[VDISCARD] = 0;     /* Ctrl-u */
        mNewOptions.c_cc[VWERASE]  = 0;     /* Ctrl-w */
        mNewOptions.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
        mNewOptions.c_cc[VEOL2]    = 0;     /* '\0' */

        tcflush(mFileDescriptor, TCIFLUSH);
        tcsetattr(mFileDescriptor,TCSANOW,&mNewOptions);
        fcntl(mFileDescriptor, F_SETFL, 0);
    }

    int SerialCommunicator::GetFD() {
        return mFileDescriptor;
    }

    void SerialCommunicator::Write(std::string pContent) {
        write(mFileDescriptor , pContent.c_str() , pContent.length());
    }

    std::string SerialCommunicator::Read(unsigned int pLength) {
        std::string retval = "";
        while (retval.length() < pLength)
            retval += ReadChar();
        return retval;
    }

    int SerialCommunicator::Read(RawData& pRawData , unsigned char pDelim) {
        unsigned char tChar = 0;

        int tReadLength = 0;
        try {
            do {
                pRawData.WriteChar(tChar);
                tChar = ReadChar();
                tReadLength++;
            } while (tChar != pDelim);

            pRawData.WriteChar(tChar);
        }
        catch (...) {
            std::cout << "Serial Read Exception" << std::endl;
        }

        return tReadLength;
    }

    int SerialCommunicator::Write(RawData& pRawData) {
        int tWriteLength = 0;
        try {
            for (unsigned int i = 0 ; i < pRawData.GetLength() ; i++) {
                WriteChar(pRawData[i]);
                tWriteLength++;
            }
        }
        catch (...) {
            std::cout << "Serial Write Exception" << std::endl;
        }

        return tWriteLength;
    }

    unsigned char SerialCommunicator::ReadChar() {
        unsigned char retval;
        int tLength = read(mFileDescriptor , &retval , 1);
        if (tLength <= 0)
            Error();
        return retval;
    }

    void SerialCommunicator::WriteChar(unsigned char pChar) {
        ssize_t tLength = write(mFileDescriptor , &pChar , 1);
        if (tLength <= 0)
            Error();
    }

    void SerialCommunicator::Close() {
        close(mFileDescriptor);
    }

    void SerialCommunicator::Error() {
        throw SerialException();
    }

    SerialCommunicator::~SerialCommunicator()
    {
        //dtor
    }

}
